home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Development Kits / HyperCard Related / XCMDs & XFCNs / Help XFCN 1.4 / source / help.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-13  |  24.8 KB  |  989 lines  |  [TEXT/MPS ]

  1. /* -----------------------------------------------------------------
  2.     File:            help.c
  3.                     XFCN to do 7.0 Help stuff
  4.     
  5.     Version:        see kVersionStr below
  6.     
  7.     History:        11-06-90 Alias    1.0d1 JRP    from volCheck.c
  8.                     11-12-90         1.0d2 JRP    put version stuff in vers.h
  9.                     11-13-90         1.0d3 JRP    add trap and gestalt checking
  10.                     11-14-90 Help    1.0d1 JRP    add findStringResId
  11.                                                 revise cmpStrtoResNum
  12.                                                 revise returnMsgNum
  13.                                                 remove alias-specific functions
  14.                                                 revise vers.h content and usage
  15.                     11-16-90 1.0d2 JRP    add ShowIfBalloon
  16.                     11-29-90 1.0d3 JRP    add gfun.c stuff
  17.                                         add getHotRect for ShowBalloon
  18.                     12-04-90 1.0d4 JRP    hotRect works only if the user has
  19.                                         show balloons turned on.
  20.                     01-18-91 1.1d1 JRP    major revision for 7.0b3
  21.                                         set ShowBalloon == ShowIfBalloon
  22.                                         add commands On, Off, and Disable
  23.                     02-19-91 1.2d1 JRP    additional parameters for Mr.Big
  24.                     09-23-91 1.3d1 JRP    add ShowBalloonRes command
  25.                     09-Apr-93 1.4  JRP    fix bug in Gestalt call that cause "Write to NIL".
  26.     
  27.     Author:            John R. Powers, III
  28.                     Electronic Media Group
  29.                     Instructional Products Department
  30.                     Apple Computer, Inc.
  31.                     AppleLink: JohnPowers
  32.     
  33.     Copyright:        see vers.h and "copyright" below.
  34.  
  35.     Computer:        Mac Quadra 950 with System 7.1
  36.     
  37.     Compiler:        MPW 3.2.2
  38.  
  39.     Usage:
  40.     
  41.         
  42.         Requires HyperCard version 1.2 or better.
  43.         There are HyperCard callbacks in this XFCN,
  44.         see gfun.c for callback information.
  45.         
  46.     Files:
  47.     
  48.         vers.h            header with version information
  49.         help.c            This source file
  50.         help.r            Rez source
  51.         gfun.c            source for using HyperCard globals
  52.         gfun.pro        prototypes for gfun.c
  53.         trap.c            source for using Gestalt
  54.         trap.pro        prototypes for trap.c
  55.         buildHelp        sets up and executes the make
  56.         makefileHelp    make file
  57.         helpLab            HyperCard stack for testing
  58.         
  59.     Full Build:
  60.     
  61.         see makefileHelp and the buildXCMD script
  62.         
  63.         buildXCMD "gfxPak:XCMDs:Mr.Big:Help:", "Help", "helpLab"
  64.     
  65.     Parameter Usage for the ShowBalloon command:
  66.     
  67.         The following table shows the required parameters
  68.         for each type of ShowBalloon (added 1.2d1):
  69.         
  70.         type      cmd      text      tip      rect      entry      inset
  71.         
  72.         basic        1        2        3
  73.         
  74.         interm.A    1        2        3        4
  75.         
  76.         interm.B    1        2                4        5
  77.         
  78.         advanced    1        2                4        5        6
  79.         
  80.         basic        puts up balloon variant #0 at the tip location
  81.                     you specify.
  82.         
  83.         interm.A    puts up balloon variant #0 at the tip location
  84.                     you specify and passes a hot rect to HM.
  85.                     
  86.         interm.B    puts up the best balloon variant for the
  87.                     quadrant in which entry is located using
  88.                     a fixed inset for the tip. (added 1.2d1)
  89.         
  90.         advanced    puts up the best balloon variant for the
  91.                     quadrant in which entry is located and uses
  92.                     your inset for the tip. (added 1.2d1)
  93.  
  94.         
  95. ----------------------------------------------------------------- */
  96.  
  97. #include    <HyperXCmd.h>
  98. #include    <Types.h>
  99. #include    <CType.h>
  100. #include    <String.h>        /*    strcpy....    */
  101. #include    <Strings.h>        /*    c2pstr....    */
  102. #include    <Memory.h>
  103. #include    <ToolUtils.h>
  104. #include    <Resources.h>
  105. #include    <Packages.h>
  106. #include    <Files.h>
  107. #include    <Errors.h>
  108.  
  109. #include    <Balloons.h>
  110.  
  111. /*
  112.         Constants
  113. */
  114.  
  115. #define        kCterm                '\0'
  116. #define        kColon                ':'
  117. #define        kReturn                '\n'
  118. #define        kComma                ','
  119. #define        kSpace                ','
  120. #define        kCommaStr            ","
  121. #define        kReturnStr            "\n"
  122. #define        kSpaceStr            " "
  123. #define        kNoStringResource    "Err 00 Missing STR# for "
  124.  
  125. #include "vers.h"                /*     version and copyright info            */
  126.  
  127. enum                            /*    STR indices                        */
  128.     {
  129.         ksCmdVersion=1,            /*    first of commands                    */
  130.         ksCmdHelp,
  131.         ksCmdShowBalloon,
  132.         ksCmdShowBalloonRes,    // 09-23-91 1.3d1 added
  133.         ksCmdRemoveBalloon,
  134.         ksCmdShowIfBalloon,
  135.         ksCmdOn,
  136.         ksCmdOff,
  137.         ksCmdDisable,
  138.         ksHelpDesc,                /*    help description                    */
  139.         ksGlobalName,            /*    name of our HyperCard global        */
  140.         ksErrCommandWhere,        /*    first of error messages                */
  141.         ksErrCommandHuh,
  142.         ksErrParameters,
  143.         ksErrNoHelpMgr,
  144.         ksErrPointParam,
  145.         ksErrRectParam,
  146.         ksErrShowBalloon,
  147.         ksErrSetBalloons,
  148.         ksErrRemoveBalloon,
  149.         ksErrNoMemory,
  150.         ksErrStoreGlobal,
  151.         ksErrHelpNotOn,
  152.         ksErrNotYet
  153.     };
  154.  
  155. enum                            /*    parameter indices                    */
  156.     {
  157.         kParamCmd,                /*    command                                */
  158.         kParamText,                /*    help message text                    */
  159.         kParamLevel=kParamText,    /*    level number                        */
  160.         kParamTip,                /*    location for balloon tip            */
  161.         kParamRect,                /*    hot rectangle                        */
  162.         kParamEntry,            /*    point of entry into object            */
  163.         kParamOffset,            /*    tip offset                            */
  164.         kParamResName=kParamText,    // STR# resource name (alternative)
  165.         kParamResInx                // STR# index (alternative)
  166.     };
  167.                                 /*    The ShowBalloon command requires    */
  168.                                 /*    a minimum of 3, 4, or 5 parameters    */
  169. #define    kMinParamShowA        3
  170. #define    kMinParamShowB        5
  171.                                 /*    default tip offsets                    */
  172. #define    kOffsetHorz            10
  173. #define    kOffsetVert            10
  174.  
  175. enum                            /*    tip location variants in HM            */
  176.     {
  177.         kTip0=0,                /*    starts at 10 o'clock and goes CW    */
  178.         kTip1,
  179.         kTip2,
  180.         kTip3,
  181.         kTip4,
  182.         kTip5,
  183.         kTip6,
  184.         kTip7
  185.     };
  186.  
  187. /*
  188.         Macros
  189. */
  190.  
  191. #define        ABS(x)        (((x)<0)?(-(x)):(x))
  192.  
  193. /*
  194.         Structures
  195. */
  196.  
  197. typedef union {                    /*    for our Rect manipulations            */
  198.         Rect    altRect;
  199.         struct {
  200.             Point    topLeft;
  201.             Point    botRight;
  202.         } altPoints;
  203.     }    rectRecType, *rectPtrType, **rectHanType;
  204.  
  205. /*
  206.         Prototypes
  207. */
  208.  
  209. void addStrItemToList(char *, char *);
  210. void addNumItemToList(char *, long);
  211. short cmpStrtoResNum(Str255, short, short);
  212. void copyPtoCstr(char *, Str255);
  213. Handle copyStrToHand(char *);
  214. short equalPstr(Str255, Str255);
  215. short findStrResId(Str255);
  216. short getHotRect(XCmdPtr, Str255, short, Rect **, Str255);
  217. void getItemFromCList(char *, short, char *);
  218. void getItemFromPList(Str255, short, Str255);
  219. void handleToCstr(char *, Handle);
  220. void handleToNum(long *, Handle);
  221. void handleToPstr(Str255, Handle);
  222. short pointFromPstr(Point *, Str255);
  223. short rectFromPstr(Rect *, Str255);
  224. void returnMsgNum(XCmdPtr, short, short, long);
  225. void selectBalloon(Point *, short *, Point *, Rect *, Point *);
  226.  
  227. #include    "trap.pro"
  228. #include    "gfun.pro"
  229.  
  230. /*
  231.     DEBUG_MSG_HAN(msg, han) displays the message, msg,
  232.     and dumps the memory referenced by the handle, han.
  233. */
  234.  
  235. #define        DEBUG_MSG_HAN(msg, han)                            \
  236.             {                                                \
  237.                 char debugCstr[50],hexCstr[10];                \
  238.                 strcpy(debugCstr,msg);                        \
  239.                 strcat(debugCstr," ;dm ");                    \
  240.                 convertHanToHexStr(hexCstr, (Handle) han);    \
  241.                 strcat(debugCstr,hexCstr);                    \
  242.                 strcat(debugCstr, "^ ");                    \
  243.                 DebugStr((Str255)c2pstr(debugCstr));        \
  244.             }
  245. /*
  246.     Set kccDbAltRect true to debug (display) the
  247.     alternativeRect.
  248. */
  249.  
  250. #define        kccDbAltRect        false
  251.  
  252. /*
  253.         Main program and entry point for XFCN.
  254. */
  255.  
  256. pascal void    entryPoint(paramPtr)
  257. /*
  258. */
  259.  
  260.     XCmdPtr         paramPtr;        /*    the HyperCard connection    */
  261. {
  262.     char            resultStr[1024],
  263.                     copyright[]=kCopyrightStr;
  264.     Str255            command,
  265.                     pointPstr,
  266.                     globalNamePstr;
  267.     OSErr            err;
  268.     short            strResId,
  269.                     turnOn,
  270.                     tipProvided;
  271.     long            level;
  272.     short            paramInxOffset;
  273.     char            resNameStr[64];
  274.     Str255            resInxStr;
  275.     long            resIndex;
  276.                                 /*    Help manager structures            */
  277.     HMMessageRecord    HMR;
  278.     Point            tip,
  279.                     entryLoc,
  280.                     tipInset;
  281.     Ptr                pTipProc;
  282.     short            theProc,
  283.                     variant,
  284.                     method;
  285.     Rect             *pQdRect;        /*    pointer to saved Rect        */
  286.     
  287.     *resultStr = kCterm;
  288.     if(paramPtr->paramCount<0)
  289.         return;                    /*    an event, ignore                */
  290.                                 /*    Get the string resource ID        */
  291.                                 /*    for our named STR#                */
  292.     strResId = findStrResId(kProgNameStr);
  293.     if(!strResId)
  294.     {                            /*    Oh-oh, our STR# is missing        */
  295.         strcpy(resultStr, kNoStringResource);
  296.         strcat(resultStr, kProgNameStr);
  297.         paramPtr->returnValue = copyStrToHand(resultStr);
  298.         return;
  299.     }
  300.                                 /*    get our global, if any            */
  301.     GetIndString(globalNamePstr, strResId, ksGlobalName);
  302.                                 /*    check for command                */
  303.     if(paramPtr->paramCount==0)
  304.     {
  305.         returnMsgNum(paramPtr, ksErrCommandWhere, strResId, 0);
  306.         return;
  307.     }
  308.     handleToPstr(command, paramPtr->params[kParamCmd]);
  309.                                 /*    version command?                */
  310.     if(cmpStrtoResNum(command, ksCmdVersion, strResId))
  311.     {
  312.         strcpy(resultStr, kProgNameStr);
  313.         strcat(resultStr, kSpaceStr);
  314.         strcat(resultStr, kVersionStr);
  315.         strcat(resultStr, kSpaceStr);
  316.         strcat(resultStr, kAuthorStr);
  317.         paramPtr->returnValue = copyStrToHand(resultStr);
  318.         return;
  319.     }
  320.                                 /*    help command?                    */
  321.     else if(cmpStrtoResNum(command, ksCmdHelp, strResId))
  322.     {
  323.         returnMsgNum(paramPtr, ksHelpDesc, strResId, 0);
  324.         return;
  325.     }
  326.     else if(!helpMgrPresent())    /*    check for Help Manager            */
  327.     {
  328.         returnMsgNum(paramPtr, ksErrNoHelpMgr, strResId, 0);
  329.         return;
  330.     }
  331.                                 /*    The following commands require    */
  332.                                 /*    the Help Manager                */
  333.  
  334.                                 /*    The show commands require        */
  335.                                 /*    that Balloon Help be enabled    */
  336.                                 /*    If it isn't, return right now.    */
  337.     if(!HMGetBalloons()
  338.         && (cmpStrtoResNum(command, ksCmdShowBalloon, strResId)
  339.             ||
  340.             cmpStrtoResNum(command, ksCmdShowIfBalloon, strResId)))
  341.     {
  342.         paramPtr->returnValue = nil;
  343.         return;
  344.     }
  345.                                 /*    Check for On or Off.            */
  346.                                 /*    If either, then the state of    */
  347.                                 /*    turnOn is the desired state.    */
  348.     if((turnOn = cmpStrtoResNum(command, ksCmdOn, strResId))
  349.         || cmpStrtoResNum(command, ksCmdOff, strResId))
  350.     {
  351.         if(err = HMSetBalloons(turnOn))
  352.         {
  353.             returnMsgNum(paramPtr, ksErrSetBalloons, strResId, err);
  354.             return;
  355.         }
  356.         else
  357.         {
  358.             paramPtr->returnValue = nil;
  359.             return;
  360.         }
  361.     }
  362.                                 /*    Disable, level?                    */
  363.     if(cmpStrtoResNum(command, ksCmdDisable, strResId))
  364.     {
  365.         if(paramPtr->paramCount<2)
  366.             level = 0;
  367.         else
  368.             handleToNum(&level, paramPtr->params[kParamText]);
  369.                                 /*    At this point, we need to make    */
  370.                                 /*    some neat call to HM to set the    */
  371.                                 /*    disable level (Right after        */
  372.                                 /*    Randy implements it.)            */
  373.         returnMsgNum(paramPtr, ksErrNotYet, strResId, 0);
  374.         return;
  375.     }
  376.  
  377.                                 /*    ShowBalloon    or                    */
  378.                                 /*    ShowBalloonSTR or                */
  379.                                 /*    ShowIfBalloon command?            */
  380.     if(cmpStrtoResNum(command, ksCmdShowBalloon, strResId)
  381.         || cmpStrtoResNum(command, ksCmdShowIfBalloon, strResId)
  382.             || cmpStrtoResNum(command, ksCmdShowBalloonRes, strResId))
  383.     {
  384.         if(cmpStrtoResNum(command, ksCmdShowBalloonRes, strResId))
  385.         {            // ShowBalloonRes (STR resource name and index)
  386.             paramInxOffset = 1; // use alternative parameter indexes
  387.             if(paramPtr->paramCount<(kMinParamShowA+paramInxOffset))
  388.             {                    /*    not enough parameters            */
  389.                 returnMsgNum(paramPtr, ksErrParameters, strResId, 0);
  390.                 return;
  391.             }
  392.             HMR.hmmHelpType = khmmStringRes;
  393.                     // get STR# name, convert to ID
  394.             handleToCstr(resNameStr, paramPtr->params[kParamResName]);
  395.             HMR.u.hmmStringRes.hmmResID = findStrResId(resNameStr);
  396.                     // get STR# index
  397.             handleToPstr(resInxStr, paramPtr->params[kParamResInx]);
  398.             StringToNum(resInxStr, &resIndex);
  399.             HMR.u.hmmStringRes.hmmIndex = (short) resIndex;
  400.         }
  401.         else
  402.         {            // ShowBalloon or ShowIfBalloon
  403.             paramInxOffset = 0; // use default parameter indexes
  404.             if(paramPtr->paramCount<kMinParamShowA)
  405.             {                    /*    not enough parameters            */
  406.                 returnMsgNum(paramPtr, ksErrParameters, strResId, 0);
  407.                 return;
  408.             }
  409.                                 /*    get text of help                */
  410.             HMR.hmmHelpType = khmmString;
  411.             handleToPstr((Str255) HMR.u.hmmString, paramPtr->params[kParamText]);
  412.         }
  413.                                 /*    then the tip                    */
  414.         variant = kTip0;        /*    default balloon tip variant        */
  415.         handleToPstr(pointPstr, paramPtr->params[kParamTip+paramInxOffset]);
  416.         if(tipProvided=(pointPstr[0]>0))
  417.         {
  418.             if(!pointFromPstr(&tip, pointPstr))
  419.             {
  420.                 returnMsgNum(paramPtr, ksErrPointParam, strResId, 0);
  421.                 return;
  422.             }
  423.             LocalToGlobal(&tip);
  424.         }
  425.         if(paramPtr->paramCount<=(kMinParamShowA+paramInxOffset))
  426.             pQdRect = nil;        /*    no hot rect parameter            */
  427.         else                    /*    optional hot rect                */
  428.         {
  429.             Str255 rectPstr;
  430.             
  431.             handleToPstr(rectPstr, paramPtr->params[kParamRect+paramInxOffset]);
  432.             if(!getHotRect(paramPtr, globalNamePstr, strResId, &pQdRect, rectPstr))
  433.             {                    /*    error, message already setup    */
  434.                 return;
  435.             }
  436.         }
  437.         if(!tipProvided)
  438.         {                        /*    empty point, need other params    */
  439.             if(paramPtr->paramCount<kMinParamShowB)
  440.             {                    /*    not enough parameters            */
  441.                 returnMsgNum(paramPtr, ksErrParameters, strResId, 0);
  442.                 return;
  443.             }
  444.                                 /*    entry point into object            */
  445.             handleToPstr(pointPstr, paramPtr->params[kParamEntry+paramInxOffset]);
  446.             if(!pointFromPstr(&entryLoc, pointPstr))
  447.             {
  448.                 returnMsgNum(paramPtr, ksErrPointParam, strResId, 0);
  449.                 return;
  450.             }
  451.             LocalToGlobal(&entryLoc);
  452.                                 /*    offset for balloon tip            */
  453.             handleToPstr(pointPstr, paramPtr->params[kParamOffset+paramInxOffset]);
  454.             if(pointPstr[0]==0)
  455.             {                    /*    empty, use defaults                */
  456.                 tipInset.h = kOffsetHorz;
  457.                 tipInset.v = kOffsetVert;
  458.             }
  459.             else if(!pointFromPstr(&tipInset, pointPstr))
  460.             {
  461.                 returnMsgNum(paramPtr, ksErrPointParam, strResId, 0);
  462.                 return;
  463.             }
  464.             selectBalloon(&tip, &variant, &entryLoc, pQdRect, &tipInset);
  465.         }    
  466.         pTipProc = nil;
  467.         theProc = 0;
  468.         method = kHMRegularWindow;
  469.         err = HMShowBalloon(&HMR, tip, pQdRect, pTipProc,
  470.                                             theProc, variant, method);
  471.         if(err)
  472.         {
  473.             returnMsgNum(paramPtr, ksErrShowBalloon, strResId, err);
  474.             return;
  475.         }
  476.         paramPtr->returnValue = nil;
  477.         return;
  478.     }
  479.                                 /*    RemoveBalloon command?            */
  480.     if(cmpStrtoResNum(command, ksCmdRemoveBalloon, strResId))
  481.     {
  482.         if(HMIsBalloon())
  483.             if(err = HMRemoveBalloon())
  484.             {
  485.                 returnMsgNum(paramPtr, ksErrRemoveBalloon, strResId, err);
  486.                 return;
  487.             }
  488.         paramPtr->returnValue = nil;
  489.         return;
  490.     }
  491.     else
  492.     {
  493.         returnMsgNum(paramPtr, ksErrCommandHuh, strResId, 0);
  494.         return;
  495.     }
  496. }    /*    --------------------------------------------    entryPoint    */
  497.  
  498. /*
  499.         Functions
  500. */
  501.  
  502. void addNumItemToList(pList, num)
  503. /*
  504.     Add num to pList.
  505.     
  506.     Preceed each item with a comma.
  507.     The comma will not be added as
  508.     the first item in a string or
  509.     the first item in a line.
  510. */
  511.     char    *pList;
  512.     long    num;
  513. {
  514.     Str255    tempPstr;
  515.  
  516.     NumToString(num, tempPstr);
  517.     addStrItemToList(pList, p2cstr(tempPstr));
  518. }    /*    --------------------------------------------    addNumItemToList    */
  519.  
  520. void addStrItemToList(pList, pAdd)
  521. /*
  522.     Add pAdd to pList.
  523.     
  524.     Preceed each item with a comma.
  525.     The comma will not be added as
  526.     the first item in a string or
  527.     the first item in a line.
  528. */
  529.     char    *pList,
  530.             *pAdd;
  531. {
  532.     short    len;
  533.     
  534.     if(len=strlen(pList))
  535.         if(pList[len-1]!=kReturn)
  536.             strcat(pList, kCommaStr);
  537.     strcat(pList, pAdd);
  538. }    /*    --------------------------------------------    addStrItemToList    */
  539.  
  540. short cmpStrtoResNum(theString, theStrNum, strResId)
  541. /*
  542.  
  543.     08/17/90 1.0a2 MJP    new (GFXMenu)
  544.     11-14-90 1.0d1 JRP    add strResId as parameter
  545. */
  546.     Str255        theString;
  547.     short        theStrNum,
  548.                 strResId;
  549.     
  550. {
  551.     Str255        ResString;
  552.     
  553.     GetIndString(ResString, strResId, theStrNum);
  554.     return (equalPstr(ResString, theString));
  555. }    /*    --------------------------------------------    cmpStrtoResNum    */
  556.  
  557. void copyPtoCstr(Cstr, Pstr)
  558. /*
  559.     Copy the Pstr to the Cstr.
  560.     Don't do it in-place like p2cstr.
  561. */
  562.     Str255    Pstr;
  563.     char    *Cstr;
  564. {
  565.     short    i;
  566.     
  567.     for(i=1; i<=Pstr[0]; i++)
  568.         *Cstr++ = Pstr[i];
  569.     *Cstr = 0;
  570. }    /*    --------------------------------------- copyPtoCstr            */
  571.  
  572. Handle copyStrToHand(str)
  573. /*
  574.     Create a handle and copy the string to it.
  575.     Return the handle.
  576. */
  577.     char *str;
  578. {
  579.     Handle    newHndl;
  580.  
  581.     newHndl = (Handle) NewHandle((long) strlen(str) + 1);
  582.     HLock(newHndl);
  583.     strcpy(*newHndl, str);
  584.     HUnlock(newHndl);
  585.     return(newHndl);
  586. }    /*    --------------------------------------------    copyStrToHand        */
  587.  
  588. short equalPstr(s1, s2)
  589. /*
  590.     Compare s1 and s2.
  591.     If their contents are equal and they are of equal length, return TRUE.
  592.     Comparison is not case-sensitive.
  593. */
  594.     Str255    s1,
  595.             s2;
  596. {
  597.     short    i,
  598.             c1,
  599.             c2;
  600.     
  601.     if(s1[0]!=s2[0])
  602.         return false;
  603.     for(i=1; i<=s1[0]; i++)
  604.     {
  605.         c1 = tolower(s1[i]);
  606.         c2 = tolower(s2[i]);
  607.         if(c1!=c2)
  608.             return false;
  609.     }
  610.     return true;
  611. }    /*    --------------------------------------------    equalPstr            */
  612.  
  613. short findStrResId(resName)
  614. /*
  615.     Given the name of a STR# resource, return
  616.     its ID number.  This lets us use names instead
  617.     of ID's for tracking STR# resources.
  618. */
  619.     char    *resName;
  620. {
  621.     Handle    hRes;
  622.     short    theID;
  623.     ResType    theType;
  624.     Str255    theName;
  625.     
  626.     strcpy(theName, resName);
  627.     hRes = GetNamedResource('STR#', c2pstr(theName));
  628.     if(!hRes || ResError())
  629.         return 0;
  630.     GetResInfo(hRes, &theID, &theType, theName);
  631.     if(ResError()==resNotFound)
  632.         return 0;
  633.     else
  634.         return theID;
  635. }    /*    --------------------------------------------    findStrResId        */
  636.  
  637. short getHotRect(paramPtr, globalNamePstr, strResId, ppQdRect, rectPstr)
  638. /*
  639.     Return the pQdRect after extracting and converting
  640.     the HyperCard local rectangle on the parameter list.
  641.     
  642.     11-30-90 1.0d3 JRP    new
  643.     12-03-90 1.0d4 JRP    must return ppQdRect by reference, not value
  644.     
  645.     Return true if successful, false if error
  646. */
  647.     XCmdPtr         paramPtr;
  648.     Str255            globalNamePstr;
  649.     short            strResId;
  650.     Rect            **ppQdRect;        /*    pointer to the Rect Ptr        */
  651.     Str255            rectPstr;        /*    HC rect in string form        */
  652. {
  653.     Rect            hcRect;            /*    HC rect in HC rect form        */
  654.     Handle            hHelpRect;        /*    handle to saved Rect        */
  655.     rectPtrType        pHelpRect;        /*    local copy of rect pointer    */
  656.  
  657.     *ppQdRect = nil;
  658.     if(!fetchHanFromGlobal(paramPtr, globalNamePstr, &hHelpRect))
  659.     {                    /*    create storage for hot rect        */
  660.         hHelpRect = NewHandleClear(sizeof(rectRecType));
  661.         if(hHelpRect==nil || MemError())
  662.         {                /*    couldn't get memory for rect    */
  663.             returnMsgNum(paramPtr, ksErrNoMemory, strResId, 0);
  664.             return false;
  665.         }
  666.         MoveHHi(hHelpRect);
  667.         if(storeHanInGlobal(paramPtr, globalNamePstr, hHelpRect))
  668.         {                /*    error storing global            */
  669.             returnMsgNum(paramPtr, ksErrStoreGlobal, strResId, 0);
  670.             return false;
  671.         }
  672.     }
  673.                         /*    get optional HyperCard rect        */
  674.     if(!rectFromPstr(&hcRect, rectPstr))
  675.     {
  676.         returnMsgNum(paramPtr, ksErrRectParam, strResId, 0);
  677.         return false;
  678.     }
  679.                         /*    our saved rect storage            */
  680.     HLock(hHelpRect);
  681.     pHelpRect = (rectPtrType) *hHelpRect;
  682.                         /*    HyperCard to QuickDraw Rect        */
  683.                         /*    copy to saved rect storage        */
  684.     pHelpRect->altRect.top = hcRect.left;
  685.     pHelpRect->altRect.left = hcRect.top;
  686.     pHelpRect->altRect.bottom = hcRect.right;
  687.     pHelpRect->altRect.right = hcRect.bottom;
  688.     #if    kccDbAltRect
  689.         DEBUG_MSG_HAN("After, QD Rect, Local", hHelpRect);
  690.     #endif
  691.                         /*    Local to Global Coordinates        */
  692.     LocalToGlobal(&(pHelpRect->altPoints.topLeft));
  693.     LocalToGlobal(&(pHelpRect->altPoints.botRight));
  694.     #if    kccDbAltRect
  695.         DEBUG_MSG_HAN("After, QD Rect, Global", hHelpRect);
  696.     #endif
  697.     *ppQdRect = (Rect *) pHelpRect;    /*    return ptr to rect    */
  698.     return true;        /*    success                            */
  699. }    /*    --------------------------------------------    getHotRect        */
  700.  
  701. void getItemFromCList(itemListCstr, itemNum, itemCstr)
  702. /*
  703.     Return the itemNum-th item in the itemListCstr.
  704.     Stops at end of string or Return character (end of HyperCard line).
  705.     Returns terminator if item not present.
  706.     Does not return any punctuation (comma or return).
  707. */
  708.     char    *itemListCstr;
  709.     short    itemNum;
  710.     char    *itemCstr;
  711. {
  712.     short    itemCnt=1;
  713.  
  714.                                     /*    Count commas to get itemNum-th item    */
  715.     while(itemCnt<itemNum && *itemListCstr!=0 && *itemListCstr!=kReturn)
  716.         if(*itemListCstr++==kComma)
  717.             itemCnt++;
  718.                                     /*    Copy itemNum-th item                */
  719.                                     /*    skip leading spaces                    */
  720.     if(itemCnt==itemNum)
  721.     {
  722.         while(*itemListCstr!=0 && *itemListCstr!=kReturn && *itemListCstr==kSpace)
  723.             itemListCstr++;
  724.         while(*itemListCstr!=0 && *itemListCstr!=kReturn && *itemListCstr!=kComma)
  725.             *itemCstr++ = *itemListCstr++;
  726.     }
  727.     *itemCstr = kCterm;
  728.         
  729. }    /*    --------------------------------------------    getItemFromCList        */
  730.  
  731. void getItemFromPList(itemListPstr, itemNum, itemPstr)
  732. /*
  733.     Return the itemNum-th item in the itemListPstr
  734. */
  735.     Str255    itemListPstr;
  736.     short    itemNum;
  737.     Str255    itemPstr;
  738. {
  739.     short    i=1,
  740.             j=0,
  741.             itemCnt=1;
  742.                                     /*    Count commas to get itemNum-th item    */
  743.     while(itemCnt<itemNum && i<itemListPstr[0])
  744.         if(itemListPstr[i++]==kComma)
  745.             itemCnt++;
  746.                                     /*    Copy itemNum-th item                */
  747.     if(itemCnt==itemNum)
  748.         while(i<=itemListPstr[0] && itemListPstr[i]!=kComma)
  749.             itemPstr[++j] = itemListPstr[i++];
  750.     itemPstr[0] = j;
  751. }    /*    --------------------------------------------    getItemFromPList        */
  752.  
  753. void handleToCstr(str, hndl)
  754. /*
  755.     Return a copy of the string contained in the handle.
  756.     If the handle is NIL, return an empty string.
  757. */
  758.     char    *str;
  759.     Handle    hndl;
  760. {
  761.     if(hndl==nil)
  762.         *str = kCterm;
  763.     else
  764.     {
  765.         HLock(hndl);
  766.         strcpy(str, *hndl);
  767.         HUnlock(hndl);
  768.     }
  769. }    /*    --------------------------------------------    handleToCstr        */
  770.  
  771. void handleToNum(num, hndl)
  772. /*
  773.     Return the number contained the string contained in the handle.
  774.     If the handle is NIL, return zero.
  775.     
  776.     Don't want to convert the handle string from C-string to
  777.     Pascal string in-place.  Copy to a local string first.
  778. */
  779.     long    *num;
  780.     Handle    hndl;
  781. {
  782.     char    str[32];
  783.     
  784.     if(hndl==nil)
  785.         *num = 0;
  786.     else
  787.     {
  788.         HLock(hndl);
  789.         strcpy((char *)str, *hndl);
  790.         HUnlock(hndl);
  791.         StringToNum(c2pstr(str), num);
  792.     }
  793. }    /*    --------------------------------------------    handleToNum        */
  794.  
  795. void handleToPstr(str, hndl)
  796. /*
  797.     Return a copy of the string contained in the handle.
  798.     If the handle is NIL, return an empty string.
  799. */
  800.     Str255    str;
  801.     Handle    hndl;
  802. {
  803.     if(hndl==nil)
  804.         str[0] = 0;
  805.     else
  806.     {
  807.         HLock(hndl);
  808.         strcpy((char *)str, *hndl);
  809.         HUnlock(hndl);
  810.         c2pstr(str);
  811.     }
  812. }    /*    --------------------------------------------    handleToPstr        */
  813.  
  814. short pointFromPstr(tip, pointPstr)
  815. /*
  816.     Pass a Pascal string containing two coordinates
  817.     in the form "h,v".  The point will be returned
  818.     in tip.
  819.     
  820.     true is returned if successful.
  821.     false if an error.
  822. */
  823.     Point    *tip;
  824.     Str255    pointPstr;
  825. {
  826.     Str255        pointHPstr,
  827.                 pointVPstr;
  828.     long        tempLong;
  829.     
  830.     getItemFromPList(pointPstr, 1, pointHPstr);
  831.     getItemFromPList(pointPstr, 2, pointVPstr);
  832.     if(pointHPstr[0]==0 || pointVPstr[0]==0)
  833.         return false;
  834.     StringToNum(pointHPstr, &tempLong);
  835.     tip->h = tempLong;
  836.     StringToNum(pointVPstr, &tempLong);
  837.     tip->v = tempLong;
  838.     return true;
  839. }    /*    --------------------------------------------    pointFromPstr        */
  840.  
  841. short rectFromPstr(theRect, rectPstr)
  842. /*
  843.     Pass a Pascal string containing a rect
  844.     in the form "t,l,b,r".  The rect will be returned
  845.     in theRect.
  846.     
  847.     true is returned if successful.
  848.     false if an error.
  849. */
  850.     Rect    *theRect;
  851.     Str255    rectPstr;
  852. {
  853.     Str255        rectItemPstr;
  854.     long        tempLong;
  855.     short        i;
  856.     
  857.     for(i=1; i<=4; i++)
  858.     {
  859.         getItemFromPList(rectPstr, i, rectItemPstr);
  860.         if(rectItemPstr[0]==0)
  861.             return false;
  862.         StringToNum(rectItemPstr, &tempLong);
  863.         switch(i)
  864.         {
  865.             case 1:
  866.                 theRect->top = tempLong;
  867.                 break;
  868.             case 2:
  869.                 theRect->left = tempLong;
  870.                 break;
  871.             case 3:
  872.                 theRect->bottom = tempLong;
  873.                 break;
  874.             case 4:
  875.                 theRect->right = tempLong;
  876.                 break;
  877.         }
  878.     }
  879.     return true;
  880. }    /*    --------------------------------------------    rectFromPstr        */
  881.  
  882. void returnMsgNum(paramPtr, strNum, strResId, num)
  883. /*
  884.     Given the STR# number and a number,
  885.     place the string and the number
  886.     in the return to HyperCard.
  887.     The num is optional, if 0 then it is not placed.
  888.     No space or punctuation is added between the string
  889.     and the num.
  890.     
  891.     11-14-90 1.0d1 JRP    add strResId as a parameter
  892.     11-30-90 1.0d3 JRP    append num directly rather than addNumItemToList
  893. */
  894.     XCmdPtr     paramPtr;        /*    the HyperCard connection        */
  895.     short        strNum,
  896.                 strResId;
  897.     long        num;
  898. {
  899.     Str255        resPstr,
  900.                 tempPstr;
  901.     char        resultStr[256];
  902.     
  903.     GetIndString(resPstr, strResId, strNum);
  904.     strcpy(resultStr, p2cstr(resPstr));
  905.     if(num!=0)
  906.     {
  907.         NumToString(num, tempPstr);
  908.         strcat(resultStr, p2cstr(tempPstr));
  909.     }
  910.     paramPtr->returnValue = copyStrToHand(resultStr);
  911. }    /*    --------------------------------------------    returnMsgNum    */
  912.  
  913. void selectBalloon(pTipLoc, pVariant, pEntryLoc, pObjRect, pTipInset)
  914. /*
  915.     Calculate the pTipLoc and balloon tip pVariant
  916.     given:
  917.             pEntryLoc    cursor location in object
  918.             pObjRect    the object rectangle
  919.             pTipInset    the inset desired for the tip
  920.     
  921.     by computing which quadrant the pEntryLoc is in
  922.     and, from that and the pObjRect, generating a
  923.     balloon tip location, pTipLoc, and balloon tip
  924.     pVariant that will not obscure the object.
  925.     
  926.     If pTipInset.h!=pTipInset.v, this function will select
  927.     a balloon pVariant that will minimize obscuring
  928.     the pObjRect.
  929.     
  930.     
  931.     All coordinates are global.
  932.     You're right, pEntryLoc and pTipInset did not have
  933.     to be passed as pointers.  But here they are anyway.
  934. */
  935.     Point    *pTipLoc;
  936.     short    *pVariant;
  937.     Point    *pEntryLoc;
  938.     Rect    *pObjRect;
  939.     Point    *pTipInset;
  940. {
  941.     Point    middle;
  942.                                 /*    divide object into quadrants        */
  943.     middle.v = pObjRect->top
  944.                 + ((ABS(pObjRect->bottom) - ABS(pObjRect->top)) / 2);
  945.     middle.h = pObjRect->left
  946.                 + ((ABS(pObjRect->right) - ABS(pObjRect->left)) / 2);
  947.                                 /*    locate pEntryLoc in quadrant            */
  948.     if(pEntryLoc->v>middle.v)
  949.     {                            /*    below the mason-dixon line            */
  950.         pTipLoc->v = pObjRect->bottom - pTipInset->v;
  951.         if(pEntryLoc->h>middle.h)
  952.         {                        /*    southeast quadrant                    */
  953.             pTipLoc->h = pObjRect->right - pTipInset->h;
  954.             if(pTipInset->h>pTipInset->v)
  955.                 *pVariant = kTip0;
  956.             else
  957.                 *pVariant = kTip1;
  958.         }
  959.         else
  960.         {                        /*    southwest quadrant                    */
  961.             pTipLoc->h = pObjRect->left + pTipInset->h;
  962.             if(pTipInset->h>pTipInset->v)
  963.                 *pVariant = kTip3;
  964.             else
  965.                 *pVariant = kTip2;
  966.         }
  967.     }
  968.     else
  969.     {                            /*    above the mason-dixon line            */
  970.         pTipLoc->v = pObjRect->top + pTipInset->v;
  971.         if(pEntryLoc->h>middle.h)
  972.         {                        /*    northeast quadrant                    */
  973.             pTipLoc->h = pObjRect->right - pTipInset->h;
  974.             if(pTipInset->h>pTipInset->v)
  975.                 *pVariant = kTip7;
  976.             else
  977.                 *pVariant = kTip6;
  978.         }
  979.         else
  980.         {                        /*    northwest quadrant                    */
  981.             pTipLoc->h = pObjRect->left + pTipInset->h;
  982.             if(pTipInset->h>pTipInset->v)
  983.                 *pVariant = kTip4;
  984.             else
  985.                 *pVariant = kTip5;
  986.         }
  987.     }    
  988. }    /*    --------------------------------------------    selectBalloon    */
  989.